package com.huadao.cart_ccs.main;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.text.format.DateFormat;
import android.util.Log;

import com.cart.event.SerialPortEvent;
import com.huadao.cart_ccs.Event.ConsoleEvent;
import com.huadao.cart_ccs.common.ByteUtils;
import com.huadao.cart_ccs.common.ExperimentStageManager;
import com.huadao.cart_ccs.common.ParamsPreferences;
import com.huadao.cart_ccs.common.ProjectManager;
import com.huadao.cart_ccs.common.RawMessageManager;
import com.huadao.cart_ccs.common.RockToast;
import com.huadao.cart_ccs.common.deviceController.CO2Controller;
import com.huadao.cart_ccs.common.deviceController.CirculatingPumpController;
import com.huadao.cart_ccs.common.deviceController.CultureTankController;
import com.huadao.cart_ccs.common.deviceController.DoorController;
import com.huadao.cart_ccs.common.deviceController.ElectronicScaleController;
import com.huadao.cart_ccs.common.deviceController.FluidIntakePumpController;
import com.huadao.cart_ccs.common.deviceController.LiquidLevelController;
import com.huadao.cart_ccs.common.deviceController.MagneticStirrerController;
import com.huadao.cart_ccs.common.deviceController.MediumValveController;
import com.huadao.cart_ccs.common.deviceController.O2Controller;
import com.huadao.cart_ccs.common.deviceController.ReclaimPumpController;
import com.huadao.cart_ccs.common.deviceController.SalineValveController;
import com.huadao.cart_ccs.common.deviceController.ShakerValveController;
import com.huadao.cart_ccs.common.deviceController.TemperatureController;
import com.huadao.cart_ccs.common.deviceController.UltravioletLightController;
import com.huadao.cart_ccs.common.deviceController.WastePumpController;
import com.huadao.cart_ccs.data.bo.BaseBO;
import com.huadao.cart_ccs.data.bo.CO2BO;
import com.huadao.cart_ccs.data.bo.CommandWord;
import com.huadao.cart_ccs.data.bo.CultureTankBO;
import com.huadao.cart_ccs.data.bo.DoorBO;
import com.huadao.cart_ccs.data.bo.ElectronicScaleBO;
import com.huadao.cart_ccs.data.bo.LiquidLevelBO;
import com.huadao.cart_ccs.data.bo.MagneticStirrerBO;
import com.huadao.cart_ccs.data.bo.O2BO;
import com.huadao.cart_ccs.data.bo.PeristalticPumpBO;
import com.huadao.cart_ccs.data.bo.Protocol;
import com.huadao.cart_ccs.data.bo.RawMessage;
import com.huadao.cart_ccs.data.bo.TemperatureBO;
import com.huadao.cart_ccs.data.bo.UltravioletLightBO;
import com.huadao.cart_ccs.data.bo.ValveBO;
import com.huadao.cart_ccs.data.source.serialport.SerialPortSource;
import com.huadao.cart_ccs.exception.ExceptionCode;
import com.huadao.cart_ccs.exception.ExceptionType;
import com.huadao.cart_ccs.exception.ProtocolException;
import com.huadao.cart_ccs.exception.UnpackException;
import com.huadao.cart_ccs.experiment.paramsSetting.ParamConsts;
import com.huadao.cart_ccs.greendao.GreenDaoManager;
import com.huadao.cart_ccs.greendao.entity.EnvironmentParams;
import com.huadao.cart_ccs.greendao.entity.ExceptionInfo;
import com.huadao.cart_ccs.netty.TestDecoder;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.greenrobot.greendao.async.AsyncSession;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * 接收报文的Service
 */
public class CommandService extends Service {
    private static final String TAG = "CommandService";
    private AsyncSession asyncSession;
    private InputStream mInputStream;
    private Thread mReadThread;
    private TestDecoder testDecoder = new TestDecoder();
    //    private long projectId=-1;
//    private long experimentStageId=-1;
    private CommandCallBack commandCallBack;

    //    private Thread recordRawThread;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new CommandBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        asyncSession = GreenDaoManager.getInstance().getAsyncNoCacheSession();
        initSerialPort();
        EventBus.getDefault().register(this);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        closeSerialPort();
        Log.i(TAG, "串口通信服务关闭");
        super.onDestroy();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(SerialPortEvent event) {
        if (event.isIsConnected()) {
            mInputStream = SerialPortSource.instance().getInputStream();
            if (mInputStream != null) {
                if (mReadThread == null) {
                    mReadThread = new ReadThread();
                } else if (mReadThread.isInterrupted()) {
                    mReadThread.start();
                }
            }
        } else {
            if (mReadThread != null && !mReadThread.isInterrupted()) {
                mReadThread.interrupt();
            }
        }
    }

    public void setCommandCallBack(CommandCallBack commandCallBack) {
        this.commandCallBack = commandCallBack;
    }

    public void initSerialPort() {
        try {
            mInputStream = SerialPortSource.instance().getInputStream();
            if (mInputStream != null) {
                mReadThread = new ReadThread();
                mReadThread.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void closeSerialPort() {
        SerialPortSource.instance().closeSerialPort();
        if (mReadThread != null) {
            mReadThread.interrupt();
        }
    }

    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            ByteBuffer byteBuffer = ByteBuffer.allocate(128);
            while (!isInterrupted()) {
                try {
                    if (mInputStream == null) continue;
//                    if (SerialPortSource.instance().getInputStream() == null) continue;
                    byte[] buff = new byte[64];
                    int size = mInputStream.read(buff);

                    if (size != -1) {
//                        EventBus.getDefault().post(new RawConsoleEvent(ByteUtils.getHexByte(buff, 0, size)));
                        byte[] data = Arrays.copyOf(buff, size);
                        saveRawBytesIntoFile(data);
                        //byteBuffer的空间不够放,清空
                        if (size > byteBuffer.limit() - byteBuffer.position()) {
                            byteBuffer.clear();
                        }
                        byteBuffer.put(buff, 0, size);
                    } else {
                        continue;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
                //准备读数据
                byteBuffer.flip();
                byte[] dst = new byte[byteBuffer.limit()];
                byteBuffer.get(dst);
//                showToastInUI("读到的数据："+ByteUtils.getHexByte(dst,0,dst.length));
                List<byte[]> spliteBytes = null;//根据HEAD和TAIL拆包
                try {
                    spliteBytes = ByteUtils.delimiterBytes3(dst, TestDecoder.HEAD[0], TestDecoder.TAIL[0]);
                } catch (UnpackException e) {
                    e.printStackTrace();
                    StringBuilder msg = new StringBuilder();
                    msg.append(e.getLocalizedMessage());
                    if (e.getBytes() != null) {
                        String bytes = ByteUtils.getHexByte(e.getBytes(), 0, e.getBytes().length);
                        msg.append(" ");
                        msg.append(bytes);
                    }
                    asyncSession.insert(new ExceptionInfo(null, new Date(), ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), ExceptionCode.unpack, msg.toString(), ExceptionType.ERROR_SERIALPORT));
                }
                if (spliteBytes == null || spliteBytes.size() == 0) {
                    byteBuffer.clear();
                    continue;
                }
                for (int i = 0; i < spliteBytes.size(); i++) {
                    byte[] content = spliteBytes.get(i);
                    if (content[0] == TestDecoder.HEAD[0] && content[content.length - 1] == TestDecoder.TAIL[0]) {
                        onDataReceived(content);
                        if (i == spliteBytes.size() - 1) {//最后一条数据
                            byteBuffer.clear();
                        }
                    } else {
                        if (i == spliteBytes.size() - 1) {//最后一条数据
                            byteBuffer.clear();
                            if (content[0] == TestDecoder.HEAD[0]) {//有HEAD但是没TAIL,说明还没结束，等待后续数据
                                byteBuffer.put(content);
                            }
                        }
                    }
                }
            }
        }
    }

    private void onDataReceived(byte[] response) {
        try {
            EventBus.getDefault().post(new ConsoleEvent(ByteUtils.getHexByte(response, 0, response.length), ConsoleEvent.TYPE_RESPONSE, new Date()));
            Protocol result = testDecoder.decode(response);
            asyncSession.insert(result);
            BaseBO baseBO = result.parse2BO();
//            EventBus.getDefault().post(new ConsoleEvent(baseBO.toString(), ConsoleEvent.TYPE_RESPONSE, new Date()));
            updateDevice(baseBO);
            EventBus.getDefault().post(baseBO);
//            if(commandCallBack!=null){
//                commandCallBack.onCommandReceive(baseBO);
//            }
        } catch (UnpackException e) {
            e.printStackTrace();
            RockToast.showToastSafe(e.getLocalizedMessage());
            asyncSession.insert(new ExceptionInfo(null, new Date(), ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), ExceptionCode.unpack, e.getLocalizedMessage(), ExceptionType.ERROR_SERIALPORT));
        } catch (ProtocolException e) {
            e.printStackTrace();
            RockToast.showToastSafe(e.getLocalizedMessage());
            String bytes = "";
            if (e.getBytes() != null) {
                bytes = ByteUtils.getHexByte(e.getBytes(), 0, e.getBytes().length);
            }
            asyncSession.insert(new ExceptionInfo(null, new Date(), ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), e.getCode(), bytes, ExceptionType.ERROR_SERIALPORT));
        }
    }

    public class CommandBinder extends Binder {
        public void showToast(String text) {
            RockToast.showToastSafe(text);
        }

        public CommandService getService() {
            return CommandService.this;
        }
    }

    public interface CommandCallBack {
        void onCommandReceive(BaseBO baseBO);
    }

    //把接收到的数据保存到文件
    private void saveRawBytesIntoFile(final byte[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        String dateTimePattern = DateFormat.getBestDateTimePattern(Locale.CHINA, "yyyy-MM-dd HH:mm:ss");
        String date = DateFormat.format(dateTimePattern, new Date()).toString();
        RawMessage rawMessage = new RawMessage(date, ByteUtils.getHexByte(data, 0, data.length));
        RawMessageManager.getInstance().writeRawMessage(rawMessage);
    }

    //更新设备状态
    private void updateDevice(BaseBO baseBO) {
        if (baseBO.getCommondWord() == CommandWord.readFail[0] || baseBO.getCommondWord() == CommandWord.writeFail[0]) {
            return;
        }
        if (baseBO instanceof PeristalticPumpBO) {
            PeristalticPumpBO peristalticPumpBO = (PeristalticPumpBO) baseBO;
            byte modularNO = baseBO.getModularNO();
            if (modularNO == PeristalticPumpBO.PeristalticPump_fluidIntake) {
                FluidIntakePumpController.getInstance().set(peristalticPumpBO.getSpeed(), peristalticPumpBO.getDirection(), peristalticPumpBO.getAlarm());
            } else if (modularNO == PeristalticPumpBO.PeristalticPump_waste) {
                WastePumpController.getInstance().set(peristalticPumpBO.getSpeed(), peristalticPumpBO.getDirection(), peristalticPumpBO.getAlarm());
            } else if (modularNO == PeristalticPumpBO.PeristalticPump_circulating) {
                CirculatingPumpController.getInstance().set(peristalticPumpBO.getSpeed(), peristalticPumpBO.getDirection(), peristalticPumpBO.getAlarm());
            } else if (modularNO == PeristalticPumpBO.PeristalticPump_reclaim) {
                ReclaimPumpController.getInstance().set(peristalticPumpBO.getSpeed(), peristalticPumpBO.getDirection(), peristalticPumpBO.getAlarm());
            }
        } else if (baseBO instanceof CO2BO) {
            CO2BO co2BO = (CO2BO) baseBO;
            if (co2BO.getOrder() == CO2BO.read) {
                CO2Controller.getInstance().setCurrentValue(co2BO.getCO2());
                asyncSession.insert(new EnvironmentParams(null, ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), new Date(), EnvironmentParams.TYPE_CO2, co2BO.getCO2()));
            } else if (co2BO.getOrder() == CO2BO.write) {
                CO2Controller.getInstance().setSettedValue(co2BO.getCO2());
                CO2Controller.getInstance().setActivated(true);
                ParamsPreferences.getInstance().setCO2Commit(co2BO.getCO2());
            } else if (co2BO.getOrder() == CO2BO.stop) {
                CO2Controller.getInstance().setActivated(false);
            }
        } else if (baseBO instanceof O2BO) {
            O2BO o2BO = (O2BO) baseBO;
            if (o2BO.getOrder() == O2BO.read) {
                O2Controller.getInstance().setCurrentValue(o2BO.getO2());
                asyncSession.insert(new EnvironmentParams(null, ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), new Date(), EnvironmentParams.TYPE_O2, o2BO.getO2()));
            } else if (o2BO.getOrder() == O2BO.write) {
                O2Controller.getInstance().setSettedValue(o2BO.getO2());
                O2Controller.getInstance().setActivated(true);
                ParamsPreferences.getInstance().setO2Commit(o2BO.getO2());
            } else if (o2BO.getOrder() == O2BO.stop) {
                O2Controller.getInstance().setActivated(false);
            }
        } else if (baseBO instanceof TemperatureBO) {
            TemperatureBO temperatureBO = (TemperatureBO) baseBO;
            if (temperatureBO.getOrder() == TemperatureBO.read) {
                TemperatureController.getInstance().setCurrentValue(temperatureBO.getTemperature());
                asyncSession.insert(new EnvironmentParams(null, ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), new Date(), EnvironmentParams.TYPE_Temperature, temperatureBO.getTemperature()));
            } else if (temperatureBO.getOrder() == TemperatureBO.write) {
                double temp = temperatureBO.getTemperature();
                TemperatureController.getInstance().setSettedValue(temp);
                TemperatureController.getInstance().setActivated(true);
                ParamsPreferences.getInstance().setTemperatureCommit(temp - ParamsPreferences.getInstance().getTemperatureAdjust());

            } else if (temperatureBO.getOrder() == TemperatureBO.stop) {
                TemperatureController.getInstance().setActivated(false);
            }
        } else if (baseBO instanceof LiquidLevelBO) {
            LiquidLevelController.getInstance().setStatus(((LiquidLevelBO) baseBO).getStatus());
        } else if (baseBO instanceof ValveBO) {
            byte modularNO = baseBO.getModularNO();
            if (modularNO == ValveBO.Valve_medium) {
                MediumValveController.getInstance().setStatus(baseBO.getOrder());
            } else if (modularNO == ValveBO.Valve_saline) {
                SalineValveController.getInstance().setStatus(baseBO.getOrder());
            } else if (modularNO == ValveBO.Valve_shaker) {
                ShakerValveController.getInstance().setStatus(baseBO.getOrder());
            }
        } else if (baseBO instanceof ElectronicScaleBO) {
            if (baseBO.getOrder() == ElectronicScaleBO.read) {
                //读到超大值，设为0
                if (((ElectronicScaleBO) baseBO).getWeight() > ParamConsts.weight_exception) {
                    asyncSession.insert(new ExceptionInfo(null, new Date(), ProjectManager.getInstance().getProjectId(), ExperimentStageManager.getInstance().getStageId(), ExceptionCode.WEIGHT, String.valueOf(((ElectronicScaleBO) baseBO).getWeight()), ExceptionType.ERROR_LOGIC));
                    ((ElectronicScaleBO) baseBO).setWeight(0);
                }
                ElectronicScaleController.getInstance().setWeight(((ElectronicScaleBO) baseBO).getWeight());
            } else if (baseBO.getOrder() == ElectronicScaleBO.peel) {
                ElectronicScaleController.getInstance().setAd(((ElectronicScaleBO) baseBO).getAd());
            }
        } else if (baseBO instanceof MagneticStirrerBO) {
            MagneticStirrerController.getInstance().set(((MagneticStirrerBO) baseBO).getSpeed(), ((MagneticStirrerBO) baseBO).getDirection());
        } else if (baseBO instanceof CultureTankBO) {
            CultureTankController.getInstance().setSpeed(((CultureTankBO) baseBO).getSpeed());
        } else if (baseBO instanceof UltravioletLightBO) {
            UltravioletLightController.getInstance().setStatus(((UltravioletLightBO) baseBO).getStatus());
        } else if (baseBO instanceof DoorBO) {
            DoorController.getInstance().setStatus(((DoorBO) baseBO).getStatus());
        }

    }
}
